package cn.itsource.service.impl;

import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.StpUtil;
import cn.itsource.constants.Constants;
import cn.itsource.constants.ErrorCode;
import cn.itsource.exception.GlobalException;
import cn.itsource.pojo.domain.Login;
import cn.itsource.mapper.LoginMapper;
import cn.itsource.pojo.domain.Permission;
import cn.itsource.pojo.domain.Role;
import cn.itsource.pojo.dto.AdminLoginDto;
import cn.itsource.pojo.dto.LoginDto;
import cn.itsource.pojo.dto.UpdatePassword;
import cn.itsource.pojo.vo.LoginSuccessVo;
import cn.itsource.result.JSONResult;
import cn.itsource.service.ILoginService;
import cn.itsource.template.WechatTemplate;
import cn.itsource.utils.AssertUtil;
import cn.itsource.utils.CacheConstants;
import cn.itsource.utils.RConst;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 登录表 服务实现类
 * </p>
 *
 * @author tt
 * @since 2024-09-03
 */
@Service
public class LoginServiceImpl extends ServiceImpl<LoginMapper, Login> implements ILoginService {

    @Autowired
    private WechatTemplate wechatTemplate;

    @Autowired
    private LoginMapper loginMapper;

   @Autowired
   private RedisTemplate redisTemplate;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 微信登录
     * */
    @Override
    public JSONResult getToken(LoginDto loginDto) {
        String openId = wechatTemplate.getOpenId(loginDto.getCode());
        Login one = this.getOne(new LambdaQueryWrapper<Login>()
                .eq(Login::getOpenId, openId)
                .eq(Login::getType, loginDto.getType()));
        if(one!=null){
            //登录成功,保存到JWT的缓存区
            StpUtil.login(one.getId(), SaLoginConfig.setExtra(Constants.CURRENT_LOGIN_KEY,one));
            //保存到JWT的缓存区方式二:在简单模式下用，在jwt的无状态模式下不能用该方法（即后端保存不了数据）
            //StpUtil.getSession().set("currentUser",one);
            //封装对象返回给前端
            LoginSuccessVo loginSuccessVo = LoginSuccessVo.builder()
                    .phone(one.getPhone())
                    .avatar(one.getAvatar())
                    .token(StpUtil.getTokenValue())
                    .nickName(one.getNickName())
                    .login(one)
                    .build();
            return JSONResult.success(loginSuccessVo);
        }else {
            throw new GlobalException(ErrorCode.NO_USER);
        }

    }
    /**
     * 获取权限
     * */
    @Override
    public List<String> getPermissionByLoginId(Object loginId) {
        String key = CacheConstants.CURRENT_USER_PERMISSIONS+loginId;
        if(redisTemplate.hasKey(key)){
            Object o = redisTemplate.opsForValue().get(key);
            return (List<String>)o;
        }
        List<Permission> permissions = loginMapper.getPermissionByLoginId(loginId);
        List<String> collect = permissions.stream().map(Permission::getSn).collect(Collectors.toList());
        redisTemplate.opsForValue().set(key,collect, RConst.Num.INT_12, TimeUnit.HOURS);
        return collect;
    }

    /**
     * 获取角色
     * */

    @Override
    public List<String> getRoleList(Object loginId) {
        String key = CacheConstants.CURRENT_USER_ROLES+loginId;
        if(redisTemplate.hasKey(key)){
            Object o = redisTemplate.opsForValue().get(key);
            return (List<String>)o;
        }
        List<Role> roles = loginMapper.getRoleList(loginId);
        List<String> collect = roles.stream().map(Role::getSn).collect(Collectors.toList());
        redisTemplate.opsForValue().set(key,collect,RConst.Num.INT_12,TimeUnit.HOURS);
        return collect;
    }
    /**
     * 管理员登录
     * */
    @Override
    public JSONResult getAdminToken(AdminLoginDto adminLoginDto) {
        Login login = loginMapper.selectOne(new LambdaQueryWrapper<Login>()
                .eq(Login::getUsername, adminLoginDto.getUsername())
                .eq(Login::getType,RConst.Num.INT_0));
        AssertUtil.isNotNull(login,"用户名或者密码错误");

        boolean matches = passwordEncoder.matches(adminLoginDto.getPassword(), login.getPassword());
        AssertUtil.isTrue(matches,"用户名或者密码错误");
        //登录，生成token
        //StpUtil.login(login.getId());
        LoginSuccessVo loginSuccessVo = resultLogin(login);
        return JSONResult.success(loginSuccessVo);

    }

    /**
     * 修改密码
     * */
    @Override
    public JSONResult updatePassword(UpdatePassword updatePassword) {
        System.err.println(11111);
        //获取到当前登录的用户
        Login login = loginMapper.selectOne(new LambdaQueryWrapper<Login>()
                                 .eq(Login::getId, updatePassword.getLogin().getId()));
        boolean matches = passwordEncoder.matches(login.getPassword(), updatePassword.getOldPassword());
        AssertUtil.isTrue(!matches,"密码错误");
        String encode = passwordEncoder.encode(updatePassword.getNewPassword());
        login.setPassword(encode);
        loginMapper.updateById(login);
        return JSONResult.success();
    }


    private LoginSuccessVo resultLogin(Login login) {
        //登录成功,保存到JWT的缓存区
        StpUtil.login(login.getId(), SaLoginConfig.setExtra(Constants.CURRENT_LOGIN_KEY, login));
        List<String> permission = this.getPermissionByLoginId(login.getId());
        login.setPassword(null);
        //返回token 和 一些基本信息
        LoginSuccessVo loginSuccess = LoginSuccessVo.builder()
                .phone(login.getPhone())
                .avatar(login.getAvatar())
                .token(StpUtil.getTokenValue())
                .nickName(login.getNickName())
                .permissions(permission)
                .login(login)
                .build();
        //加载权限 & 角色信息到redis里面

        return loginSuccess;
    }


}
